﻿using System;
using System.Diagnostics.Contracts;

namespace Postnuclear
  {
  /// <summary>
  /// Provides some value and notifies when it's changed.
  /// </summary>
  /// <typeparam name="TValue">The type of the value.</typeparam>
  internal sealed class ValueProviderAdapter<TValue>
    {
    #region Public

    // Constructors

    /// <summary>
    /// Initializes a new instance of the <see cref="ValueProviderAdapter{TValue}"/> class.
    /// </summary>
    /// <param name="valueProvider">The value provider.</param>
    public ValueProviderAdapter(IValueProvider<TValue> valueProvider)
      {
      Contract.Requires<ArgumentNullException>(valueProvider != null);

      ValueProvider = valueProvider;

      Observer = new EventObserver<ValueEventArgs<TValue>>(Attach, Detach);
      }

    // Events

    /// <summary>
    /// Occurs when the value of the instance is changed.
    /// </summary>
    public event EventHandler<ValueEventArgs<TValue>> ValueChanged
      {
      add
        {
        Observer.Event += value;
        }

      remove
        {
        Observer.Event -= value;
        }
      }

    #endregion

    #region Private

    // Events

    private event EventHandler<ValueEventArgs<TValue>> Event;

    // Methods

    private void Attach(EventHandler<ValueEventArgs<TValue>> handler)
      {
      Event += handler;
      ValueProvider.ValueChanged += OnValueChanged;
      }

    private void Detach(EventHandler<ValueEventArgs<TValue>> handler)
      {
      Event -= handler;
      ValueProvider.ValueChanged -= OnValueChanged;
      }

    private void OnValueChanged(object sender, EventArgs e)
      {
      Event.Raise(sender, ValueProvider.Value);
      }

    // Fields

    private readonly IValueProvider<TValue> ValueProvider;
    private readonly EventObserver<ValueEventArgs<TValue>> Observer;

    #endregion
    }
  }
